#ifdef WINDOWS
#include <SDL.h>
#include <SDL_gfxPrimitives.h>
#include <SDL_ttf.h>
#endif
#ifdef LINUX
#include <SDL/SDL.h>
#include <SDL/SDL_gfxPrimitives.h>
#include <SDL/SDL_ttf.h>
#endif
#include <cmath>
#include <ctime>
#include <string>
#include <iostream>
#include "tank.h"
#include "bullet.h"
#include "weapon.h"
#include "settings.h"
#include "ground.h"
#define SPLASH          0
#define GAME            1
#define SELECTPLAYERS   2
using namespace std;

int init();
void deinit();
void update();
void draw();
int SCREEN_WIDTH = 1024;
int SCREEN_HEIGHT = 768;
int SCREEN_BPP =     32;
const int FPS = 30;
const int MAXPLAYERS =      16;
int players = 0;
SDL_Event event;
SDL_Surface *load_image( std::string filename );
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination );
SDL_Surface *screen = NULL;
SDL_Surface *splash = NULL;
SDL_Surface *gui = NULL;
SDL_Surface *tankPic = NULL;
TTF_Font *font = NULL;
SDL_Color textcolor = { 0,0,0 };
Tank *curTank[MAXPLAYERS];
BULLET *curBullet = NULL;
WEAPON *armory[20];
int game_state = SPLASH;
int next_state = SPLASH;
Ground gr;
int curPlayerNumber = 0;
bool run = true;
int begin_time = 0;
int loop_time = 0;
int wind = 20;// in px per frame

SDL_Surface *load_image( std::string filename )
{
	//Temporary storage for the image that's loaded
	SDL_Surface* loadedImage = NULL;

	//The optimized image that will be used
	SDL_Surface* optimizedImage = NULL;

	//Load the image
	loadedImage = SDL_LoadBMP( filename.c_str() );

	//If nothing went wrong in loading the image
	if ( loadedImage != NULL )
	{
		//Create an optimized image
		optimizedImage = SDL_DisplayFormat( loadedImage );
		if (optimizedImage != NULL)
		{
			Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 255, 0, 255);
			SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
		}
		//Free the old image
		SDL_FreeSurface( loadedImage );
	}

	//Return the optimized image
	return optimizedImage;
}

void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )
{
	//Make a temporary rectangle to hold the offsets
	SDL_Rect offset;

	//Give the offsets to the rectangle
	offset.x = x;
	offset.y = y;

	//Blit the surface
	SDL_BlitSurface( source, NULL, destination, &offset );
}

#undef main
int main(int argc, char* argv[])
{
	if (init() != 0)
		return 1;

	while (run)
	{
		/* put your code here */
		begin_time = clock();
		update();
		draw();
		//Update the screen
		if ( SDL_Flip( screen ) == -1 )
		{
			return 1;
		}

		loop_time = clock()-begin_time;
		int pause_time = (int)(1000/FPS)-loop_time;
		if (pause_time < 0)
			continue;
		else
			SDL_Delay(pause_time);
	}

	deinit();
	return 0;
}

int init()
{
	//Initialize all SDL subsystems
	if ( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
	{
		return 1;
	}
	Settings set("settings.skantsettings");
	SCREEN_WIDTH = set.getWidth();
	SCREEN_HEIGHT = set.getHeight();
	SCREEN_BPP = set.getColorDepth();
	if (set.getNumTanks() < MAXPLAYERS)
		players = set.getNumTanks();
	else
		players = 3;
	gr = Ground(SCREEN_WIDTH,SCREEN_HEIGHT);
	//cout << endl << "Helo" << endl;
	//Set up the screen
	screen = SDL_SetVideoMode( set.getWidth(), set.getHeight(), set.getColorDepth(), SDL_SWSURFACE );

	//If there was an error in setting up the screen
	if ( screen == NULL )
	{
		return 1;
	}
	if (TTF_Init() == -1)
		return 1;
	//cout << "Hello" << endl;
	//Set the window caption
	SDL_WM_SetCaption( "skanT", NULL );
	/* add other initializations here */
	splash = load_image("splash.bmp");
	if (!splash)
	{
		cout << "No splash.bmp" << endl;
		return 1;
	}
	gui = load_image("gui.bmp");
	if (!gui)
	{
		cout << "No gui.bmp" << endl;
		return 1;
	}
	tankPic = load_image("tank.bmp");
	if (!tankPic)
	{
		cout << "No tank.bmp" << endl;
		return 1;
	}
	font = TTF_OpenFont("font.ttf",18);
	//cout << "Helllo" << endl;
	for (int i = 0;i < players;++i)
	{
		curTank[i] = new Tank;
		curTank[i]->x = rand()%1024;
		curTank[i]->y = SCREEN_HEIGHT-200;
		curTank[i]->vel_x = 0;
		curTank[i]->vel_y = 0;
		curTank[i]->health = 100;
		curTank[i]->energy = 30;
		curTank[i]->angle = M_PI/2;
		char name[20];
		sprintf(name,"Unnamed Tank %d",i+1);
		//cout << name << endl;
		curTank[i]->name = string(name);
		//curTank[i]->name = "Name";
	}
	curBullet = new BULLET;
	curBullet->active = false;
	curBullet->radius = 40;
	curBullet->damage = 20;
	//cout << "Hellllo" << endl;
	srand(clock());
	gr.generateMap();
	//cout << "Helllllo" << endl;
	return 0;
}

void deinit()
{
	/* add other deinitializations here */
	SDL_FreeSurface(gui);
	SDL_FreeSurface(splash);
	SDL_FreeSurface(tankPic);
	SDL_Quit();
}

void update()
{
	//While there's an event to handle
	while ( SDL_PollEvent( &event ) )
	{
		if (event.type == SDL_QUIT)
		{
			run = false;
		}
	}
	Uint8 *key = SDL_GetKeyState( NULL );
	switch (game_state)
	{
		case SPLASH:
			if (key[SDLK_SPACE])
				next_state = GAME;
			if (key[SDLK_ESCAPE])
				run = false;
			break;
		case SELECTPLAYERS:
			//To be implemented!
			next_state = GAME;
			break;
		case GAME:
			for (int i = 0; i < players;++i)
			{
				if (i == curPlayerNumber)
					curTank[i]->update(true,768,1024,gr.getHeight(curTank[i]->x),key);
				else
					curTank[i]->update(false,768,1024,gr.getHeight(curTank[i]->x),key);
			}
			if (key[SDLK_ESCAPE])
				run = false;
			if (key[SDLK_RSHIFT] && !curBullet->active && curTank[curPlayerNumber]->vel_x == 0)
			{
				curBullet->active = true;
				curBullet->x = curTank[curPlayerNumber]->x;
				curBullet->y = curTank[curPlayerNumber]->y-5;
				curBullet->vel_x = (int)(cos(curTank[curPlayerNumber]->angle)*curTank[curPlayerNumber]->energy);
				curBullet->vel_y = (int)(sin(curTank[curPlayerNumber]->angle)*curTank[curPlayerNumber]->energy);
				wind = (rand()%50)-25;
			}

			if (curBullet->active)
			{
				if (curBullet->y < curTank[curPlayerNumber]->y+50)
					curBullet->x += wind;
				if (curBullet->x < 0)
				{
					curBullet->active = false;
					++curPlayerNumber;
					break;
				}
				if (curBullet->x > SCREEN_WIDTH)
				{
					curBullet->active = false;
					++curPlayerNumber;
					break;
				}
				if (curBullet->y < SCREEN_HEIGHT-gr.getHeight(curBullet->x))   // if above ground
				{
					++curBullet->vel_y;
				}
				if (curBullet->y > SCREEN_HEIGHT-gr.getHeight(curBullet->x))   // if below or on ground
				{
					curBullet->active = false;
					curBullet->vel_y = 0;
					curBullet->y = SCREEN_HEIGHT-gr.getHeight(curBullet->x);
					int takeaway = curBullet->damage;
					for (int i=0;i < curBullet->radius;++i)
					{
						gr.setHeightDelta(curBullet->x+i,-takeaway);
						gr.setHeightDelta(curBullet->x-i,-takeaway);
						if (takeaway >= 0) --takeaway;
					}
					++curPlayerNumber;
				}
				curBullet->x += curBullet->vel_x;
				curBullet->y += curBullet->vel_y;
			}
			if (key[SDLK_l])
			{
				gr.generateMap();
			}
			curPlayerNumber = curPlayerNumber % players;
			break;
		default:
			next_state = SPLASH;
	}
}

void draw()
{
	switch (game_state)
	{
		case SPLASH:
			apply_surface(0,0,splash,screen);
			break;
		case GAME:
			SDL_FillRect(screen,NULL,SDL_MapRGB(screen->format,255,255,255));
			apply_surface(0,0,gui,screen);
			for (int i=0;i < SCREEN_WIDTH;++i)
			{
				vlineColor(screen,i,SCREEN_HEIGHT-gr.getHeight(i),SCREEN_HEIGHT,SDL_MapRGB(screen->format,100,100,100));
			}
			// Tank drawing
			for (int i = 0; i < players; ++i)
			{
				apply_surface(curTank[i]->x-8,curTank[i]->y-8,tankPic,screen);
				lineRGBA(screen,
					    curTank[i]->x,
					    curTank[i]->y,
					    curTank[i]->x+(int)(cos(curTank[i]->angle)*curTank[i]->energy),
					    curTank[i]->y+(int)(sin(curTank[i]->angle)*curTank[i]->energy),
					    0,255,0,255);
				/*
				SDL_Rect* health = NULL;
				health->x = curTank[i]->x-50;
				health->y = curTank[i]->y-35;
				health->w = curTank[i]->health;
				health->h = 5;
				SDL_FillRect(screen,health,SDL_MapRGB(screen->format,100,255,100));
				*/
				if (i != curPlayerNumber)
				{
					SDL_Color light_color = {150,150,150};
					SDL_Surface *title = NULL;
					title = TTF_RenderText_Solid(font,curTank[i]->name.c_str(),light_color);
					apply_surface(curTank[i]->x-title->w/2,curTank[i]->y-30,title,screen);
					SDL_FreeSurface(title);
				}
			}

			SDL_Surface *title;
			title = TTF_RenderText_Solid(font,curTank[curPlayerNumber]->name.c_str(),textcolor);
			apply_surface(curTank[curPlayerNumber]->x-title->w/2,curTank[curPlayerNumber]->y-30,title,screen);
			SDL_FreeSurface(title);
			if (curBullet->active) filledCircleRGBA(screen,curBullet->x,curBullet->y,2,255,0,0,255);
			filledCircleRGBA(screen,512,40,5,0,0,0,255);
			hlineColor(screen,512,512+wind,40,SDL_MapRGB(screen->format,10,10,10));
			break;
		default:
			break;
	}
	if (next_state != game_state)
		game_state = next_state;
}
